# 非线性拟合！
# 采用线性化模型的解作为初始解。
from scipy.optimize import curve_fit
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
import statsmodels.api as sm

data = np.genfromtxt('data5.txt', delimiter="\t", encoding='utf-8')
# print(data)

x_data = data[:, [0]]
y_data = data[:, [1]]
# print(x_data.shape, y_data.shape)

x_train = 1 / x_data
y_train = 1 / y_data
print('数据维数：', x_train.shape, y_train.shape)

##先求解线性化模型，获得初始解

# model = LinearRegression(fit_intercept=True, normalize=False, copy_X=False)
model = LinearRegression(fit_intercept=True, normalize=False)
model.fit(x_train, y_train)  # 模型回归
print('线性化的模型参数:', model.coef_, model.intercept_)  # 输出模型参数

zz = model.predict(x_train)   #= 估计
R2 = model.score(x_train, y_train)
r2 = r2_score(y_train, zz)
mse = mean_squared_error(y_train, zz)
print('R2:', R2)


beta1 = 1 /  model.intercept_
beta2 = model.coef_[0] / model.intercept_  ## 计算出原始参数
print('转换后的参数:', beta1, beta2)

plt.scatter(x_train, y_train)
plt.plot(x_train, zz, c='r')
plt.title('采用线性化模型线性回归结果')
# plt.plot(x_train, zz2, c='r')


## 利用原始参数画图 ##################################################
################################################################
plt.figure()

def func(x, beta1, beta2):
    y = beta1 * x / (beta2 + x)
    return y

ypred = func(x_data, beta1, beta2)           #计算预测值
plt.scatter(x_data, y_data, label='真实值')
plt.scatter(x_data, ypred,marker='^', label='估计值')
plt.rcParams['font.sans-serif']=['SimHei']  #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False    #用来正常显示负
plt.legend()
plt.ylabel('反应速度')
plt.xlabel('底物浓度')
plt.title('线性化模型的估计')

xx = np.linspace(np.min(x_data), np.max(x_data), 300)##绘制光滑曲线用
zz = func(xx, beta1, beta2)
plt.plot(xx, zz, 'r')


## 下面进行非线性回归 ################################
###################################################
from scipy.optimize import curve_fit
x_data = x_data.reshape(-1)
y_data = y_data.reshape(-1)
print('数据维度：', x_data.shape, y_data.shape)

popt, pcov = curve_fit(func, x_data, y_data, p0=(beta1, beta2))
print("非线性回归参数：beta_1 = %f, beta_2 = %f" % (popt[0], popt[1]))
# print(pcov)


zz2 = func(xx, *popt)##非线性参数估计

plt.figure()
plt.scatter(x_data, y_data)
plt.plot(xx, zz, c='r', label='线性化模型')
plt.plot(xx, zz2, c='k', label='非线性方法')
plt.ylabel('反应速度')
plt.xlabel('底物浓度')
plt.legend()
plt.title('采用非线性模型结果')

plt.show()